home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Millennium Gold 2000
/
Millennium Gold 2000 - Disc 1.iso
/
HYPEROID
/
HYPEROID.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-12
|
58KB
|
1,963 lines
/*****************************************************************************/
/*HYPEROID.C - a neato game*/
/**/
/*Version: 1.1 Copyright (C) 1990,91 Hutchins Software*/
/* This software is licenced under the GNU General Public Licence*/
/* Please read the associated legal documentation*/
/**/
/*Author: Edward Hutchins*/
/*Internet: eah1@cec1.wustl.edu*/
/*USMail: c/o Edward Hutchins, 63 Ridgemoor Dr., Clayton, MO, 63105*/
/**/
/*Revisions:*/
/*10/31/91 made game better/harder - Ed.*/
/**/
/*Music: R.E.M./The Cure/Ministry/Front 242/The Smiths/New Order/Hendrix...*/
/*Beers: Bass Ale, Augsberger Dark*/
/**/
/*03/04/92 ported to Win32 - Paul Tissue & Robert Hess [Microsoft].*/
/*****************************************************************************/
#include "hyperoid.h"
/*-- imports*/
IMPORT POINT LetterPart[] FROM(roidsupp.c);
IMPORT LPSTR szNumberDesc[] FROM(roidsupp.c);
IMPORT LPSTR szLetterDesc[] FROM(roidsupp.c);
#define WINNT 0x50d
/*-- globals*/
GLOBAL CHAR szAppName[32];
GLOBAL HANDLE hAppInst;
GLOBAL HWND hAppWnd;
GLOBAL HPALETTE hAppPalette;
GLOBAL INT nDrawDelay;
GLOBAL INT nLevel;
GLOBAL INT nSafe;
GLOBAL INT nShield;
GLOBAL INT nBomb;
GLOBAL INT nBadGuys;
GLOBAL LONG lScore;
GLOBAL LONG lLastLife;
GLOBAL LONG lHighScore;
GLOBAL BOOL bRestart;
GLOBAL BOOL bPaused;
GLOBAL BOOL bBW;
GLOBAL INT vkShld;
GLOBAL INT vkClkw;
GLOBAL INT vkCtrClkw;
GLOBAL INT vkThrst;
GLOBAL INT vkRvThrst;
GLOBAL INT vkFire;
GLOBAL INT vkBomb;
GLOBAL NPOBJ npPlayer;
GLOBAL LIST FreeList;
GLOBAL LIST RoidList;
GLOBAL LIST ShotList;
GLOBAL LIST FlameList;
GLOBAL LIST SpinnerList;
GLOBAL LIST HunterList;
GLOBAL LIST HunterShotList;
GLOBAL LIST SwarmerList;
GLOBAL LIST LetterList;
GLOBAL LIST BonusList;
GLOBAL INT nCos[DEGREE_SIZE];
GLOBAL INT nSin[DEGREE_SIZE];
GLOBAL HPEN hPen[PALETTE_SIZE];
GLOBAL OBJ Obj[MAX_OBJS];
GLOBAL HBITMAP hBitmap[IDB_MAX];
GLOBAL INT isNT = FALSE;
/*-- locals*/
LOCAL DWORD dwSeed;
LOCAL INT nScoreLen;
LOCAL CHAR szScore[40];
LOCAL RECT rectScoreClip;
LOCAL RECT rectShotClip;
LOCAL POINT Player[] =
{{0, 0}, {160, 150}, {0, 250}, {96, 150}, {0, 0}};
LOCAL POINT Spinner[] =
{{160, 150}, {224, 100}, {96, 100}, {32, 150}, {160, 150}};
LOCAL POINT Swarmer[] =
{{0, 100}, {64, 100}, {128, 100}, {192, 100}, {0, 100}};
LOCAL POINT Hunter[] =
{
{160, 150}, {0, 250}, {192, 30}, {64, 30},
{0, 250}, {96, 150}, {128, 150}, {160, 150}
};
LOCAL POINT Bonus[] =
{{0, 150}, {102, 150}, {205, 150}, {51, 150}, {154, 150}, {0, 150}};
/*****************************************************************************/
/*KillBadGuy - kill off a badguy (made into a macro)*/
/*****************************************************************************/
#define KillBadGuy() \
( (--nBadGuys <= 0) ? ( SetRestart(RESTART_NEXTLEVEL), TRUE ) : FALSE )
/*****************************************************************************/
/*WinMain - everybody has to have one*/
/*****************************************************************************/
int APIENTRY
WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine,
int nCmdShow)
{
MSG msg; /* message */
#ifdef WIN32
GdiSetBatchLimit(2048);
#endif
hAppInst = hInstance;
if (!hPrevInstance) {
/* create the class if we're first */
if (!CreateHyperoidClass())
return (FALSE);
}
if (InitHyperoid()) {
hAppWnd = CreateHyperoidWindow(lpszCmdLine, nCmdShow);
if (!hAppWnd)
return (FALSE);
while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
ExitHyperoid();
return (msg.wParam);
}
/*****************************************************************************/
/*HyperoidWndProc - the main window proc for Hyperoid*/
/*****************************************************************************/
LONG APIENTRY
HyperoidWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
{
static BOOL fMyResize = FALSE;
switch (message) {
case WM_CREATE:
RestartHyperoid();
SetTimer(hWnd, DRAW_TIMER, nDrawDelay, NULL);
NCPaintHyperoid(hWnd);
break;
case WM_TIMER:
switch (wParam) {
case DRAW_TIMER:
CheckScore(hWnd);
DrawObjects(hWnd);
return (0);
case RESTART_TIMER:
KillTimer(hWnd, RESTART_TIMER);
bRestart = FALSE;
RestartHyperoid();
return (0);
}
break;
case WM_SYSCOMMAND:
switch (wParam) {
case IDM_NEW:
NewGame(hWnd);
break;
case IDM_ABOUT:
AboutHyperoid(hWnd);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_QUERYOPEN:
Panic(FALSE);
return (DefWindowProc(hWnd, message, wParam, lParam));
case WM_CHAR:
if (wParam == VK_ESCAPE)
Panic(TRUE);
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSCHAR:
if (lParam & (1L << 29)) /* alt key is down */
return (DefWindowProc(hWnd, message, wParam, lParam));
switch (wParam) {
case VK_ESCAPE:
if (message == WM_SYSKEYDOWN)
Panic(TRUE);
return (0);
case VK_SPACE:
case VK_TAB:
return (0);
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_ERASEBKGND:
return (EraseHyperoidBkgnd(hWnd, (HDC) wParam));
case WM_NCACTIVATE:
case WM_NCPAINT:
NCPaintHyperoid(hWnd);
return (TRUE);
case UM_SIZE:{
int MaxCoord = (int) max(HIWORD(lParam), LOWORD(lParam));
fMyResize = TRUE;
SetWindowPos(hWnd, (HWND)NULL, 0, 0, MaxCoord, MaxCoord,
SWP_NOMOVE | SWP_NOZORDER);
return (TRUE);
}
case WM_SIZE:{
if (wParam == SIZENORMAL && !fMyResize)
SendMessage(hWnd, UM_SIZE, wParam, lParam);
else
fMyResize = FALSE;
return (TRUE);
}
case WM_PAINT:
PaintHyperoid(hWnd);
break;
case WM_QUERYNEWPALETTE:{
HDC hDC = GetDC(hWnd);
SelectPalette(hDC, hAppPalette, 0);
RealizePalette(hDC);
ReleaseDC(hWnd, hDC);
return (TRUE);
}
case WM_DESTROY:
KillTimer(hWnd, DRAW_TIMER);
KillTimer(hWnd, RESTART_TIMER);
SaveHyperoidWindowPos(hWnd);
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0);
}
/*****************************************************************************/
/*arand - pseudorandom number from 0 to x-1 (thanks antman!)*/
/*****************************************************************************/
INT APIENTRY
arand(INT x)
{
dwSeed = dwSeed * 0x343fd + 0x269ec3;
return ((INT) (((dwSeed >> 16) & 0x7fff) * x >> 15));
}
/*****************************************************************************/
/*AddHead - add an object to the head of a list*/
/*****************************************************************************/
VOID APIENTRY
AddHead(NPLIST npList, NPNODE npNode)
{
if (npList->npHead) {
npNode->npNext = npList->npHead;
npNode->npPrev = NULL;
npList->npHead = (npList->npHead->npPrev = npNode);
}
else { /* add to an empty list */
npList->npHead = npList->npTail = npNode;
npNode->npNext = npNode->npPrev = NULL;
}
}
/*****************************************************************************/
/*RemHead - remove the first element in a list*/
/*****************************************************************************/
NPNODE APIENTRY
RemHead(NPLIST npList)
{
if (npList->npHead) {
NPNODE npNode = npList->npHead;
if (npList->npTail != npNode) {
npList->npHead = npNode->npNext;
npNode->npNext->npPrev = NULL;
}
else
npList->npHead = npList->npTail = NULL;
return (npNode);
}
else
return (NULL);
}
/*****************************************************************************/
/*Remove - remove an arbitrary element from a list*/
/*****************************************************************************/
VOID APIENTRY
Remove(NPLIST npList, NPNODE npNode)
{
if (npNode->npPrev)
npNode->npPrev->npNext = npNode->npNext;
else
npList->npHead = npNode->npNext;
if (npNode->npNext)
npNode->npNext->npPrev = npNode->npPrev;
else
npList->npTail = npNode->npPrev;
}
/*****************************************************************************/
/*DrawObject - draw a single object*/
/*****************************************************************************/
VOID APIENTRY
DrawObject(HDC hDC, NPOBJ npObj)
{
INT nCnt;
INT nDir = (npObj->nDir += npObj->nSpin);
INT x = (npObj->Pos.x += npObj->Vel.x);
INT y = (npObj->Pos.y += npObj->Vel.y);
POINT Pts[MAX_PTS];
if (x < -CLIP_COORD)
npObj->Pos.x = x = CLIP_COORD;
else if (x > CLIP_COORD)
npObj->Pos.x = x = -CLIP_COORD;
if (y < -CLIP_COORD)
npObj->Pos.y = y = CLIP_COORD;
else if (y > CLIP_COORD)
npObj->Pos.y = y = -CLIP_COORD;
for (nCnt = npObj->byPts - 1; nCnt >= 0; --nCnt) {
WORD wDeg = (WORD) DEG(npObj->Pts[nCnt].x + nDir);
INT nLen = npObj->Pts[nCnt].y;
Pts[nCnt].x = x + MULDEG(nLen, nCos[wDeg]);
Pts[nCnt].y = y + MULDEG(nLen, nSin[wDeg]);
}
if (npObj->byPts > 1) {
SelectObject(hDC, hPen[BLACK]);
Polyline(hDC, npObj->Old, npObj->byPts);
if (npObj->nCount > 0) {
SelectObject(hDC, hPen[npObj->byColor]);
Polyline(hDC, Pts, npObj->byPts);
for (nCnt = npObj->byPts - 1; nCnt >= 0; --nCnt)
npObj->Old[nCnt] = Pts[nCnt];
}
}
else { /* just a point */
#ifdef WIN32
SetPixelV(hDC, npObj->Old[0].x, npObj->Old[0].y, PALETTEINDEX(BLACK));
#else
SetPixel(hDC, npObj->Old[0].x, npObj->Old[0].y, PALETTEINDEX(BLACK));
#endif
if (npObj->nCount > 0) {
#ifdef WIN32
SetPixelV(hDC, Pts[0].x, Pts[0].y, PALETTEINDEX(npObj->byColor));
#else
SetPixel(hDC, Pts[0].x, Pts[0].y, PALETTEINDEX(npObj->byColor));
#endif
npObj->Old[0] = Pts[0];
}
}
}
/*****************************************************************************/
/*SetRestart - set the restart timer*/
/*****************************************************************************/
VOID APIENTRY
SetRestart(RESTART_MODE Restart)
{
POINT Pt;
CHAR szBuff[32];
if (bRestart)
return;
SetTimer(hAppWnd, RESTART_TIMER, RESTART_DELAY, NULL);
bRestart = TRUE;
Pt.x = Pt.y = 0;
switch (Restart) {
case RESTART_GAME:
SpinLetters("GAME OVER", Pt, Pt, RED, 400);
break;
case RESTART_LEVEL:
SpinLetters("NEXT LIFE", Pt, Pt, GREEN, 300);
break;
case RESTART_NEXTLEVEL:
wsprintf(szBuff, "LEVEL %u", nLevel + 1);
PrintLetters(szBuff, Pt, Pt, BLUE, 300);
break;
}
}
/*****************************************************************************/
/*PrintPlayerMessage - show the player a status message*/
/*****************************************************************************/
VOID APIENTRY
PrintPlayerMessage(LPSTR lpszText)
{
POINT Pos, Vel;
Pos = npPlayer->Pos;
Pos.y -= 400;
Vel.x = 0;
Vel.y = -50;
PrintLetters(lpszText, Pos, Vel, GREEN, 150);
}
/*****************************************************************************/
/*AddExtraLife - give the player another life*/
/*****************************************************************************/
VOID APIENTRY
AddExtraLife(VOID)
{
PrintPlayerMessage("EXTRA LIFE");
++npPlayer->nCount;
npPlayer->byColor = (BYTE) (BLACK + npPlayer->nCount);
if (npPlayer->byColor > WHITE)
npPlayer->byColor = WHITE;
}
/*****************************************************************************/
/*Hit - something hit an object, do fireworks*/
/*****************************************************************************/
VOID APIENTRY
Hit(HDC hDC, NPOBJ npObj)
{
INT nCnt = 0;
UNREFERENCED_PARAMETER(hDC);
for (nCnt = 0; nCnt < 8; ++nCnt) {
NPOBJ npFlame = RemHeadObj(&FreeList);
if (!npFlame)
return;
npFlame->Pos.x = npObj->Pos.x;
npFlame->Pos.y = npObj->Pos.y;
npFlame->Vel.x = npObj->Vel.x;
npFlame->Vel.y = npObj->Vel.y;
npFlame->nDir = npObj->nDir + (nCnt * DEGREE_SIZE) / 8;
npFlame->nSpin = 0;
npFlame->nCount = 6 + arand(10);
npFlame->byColor = YELLOW;
npFlame->byPts = 1;
npFlame->Pts[0].x = npFlame->Pts[0].y = 0;
ACCEL(npFlame, npFlame->nDir, 200 - npFlame->nCount);
AddHeadObj(&FlameList, npFlame);
}
}
/*****************************************************************************/
/*Explode - explode an object*/
/*****************************************************************************/
VOID APIENTRY
Explode(HDC hDC, NPOBJ npObj)
{
INT nCnt, nSize = npObj->byPts;
DrawObject(hDC, npObj);
for (nCnt = 0; nCnt < nSize; ++nCnt) {
NPOBJ npFlame;
if (arand(2))
continue;
if (!(npFlame = RemHeadObj(&FreeList)))
return;
npFlame->Pos.x = npObj->Pos.x;
npFlame->Pos.y = npObj->Pos.y;
npFlame->Vel.x = npObj->Vel.x;
npFlame->Vel.y = npObj->Vel.y;
npFlame->nDir = npObj->nDir + nCnt * DEGREE_SIZE / nSize + arand(32);
npFlame->nSpin = arand(31) - 15;
npFlame->nCount = 25 + arand(16);
npFlame->byColor = npObj->byColor;
npFlame->byPts = 2;
npFlame->Pts[0] = npObj->Pts[nCnt];
if (nCnt == nSize - 1)
npFlame->Pts[1] = npObj->Pts[0];
else
npFlame->Pts[1] = npObj->Pts[nCnt + 1];
ACCEL(npFlame, npFlame->nDir, 60 - npFlame->nCount);
AddHeadObj(&FlameList, npFlame);
}
Hit(hDC, npObj);
}
/*****************************************************************************/
/*HitPlayer - blow up the player*/
/*****************************************************************************/
BOOL APIENTRY
HitPlayer(HDC hDC, NPOBJ npObj)
{
POINT Vel;
INT nMass, nSpin;
if (nSafe || (npPlayer->nCount <= 0))
return (FALSE);
/* rumble and shake both objects */
nMass = npPlayer->nMass + npObj->nMass;
nSpin = npPlayer->nSpin + npObj->nSpin;
npObj->nSpin -= MulDiv(nSpin, npPlayer->nMass, nMass);
npPlayer->nSpin -= MulDiv(nSpin, npObj->nMass, nMass);
Vel.x = npPlayer->Vel.x - npObj->Vel.x;
Vel.y = npPlayer->Vel.y - npObj->Vel.y;
npObj->Vel.x += MulDiv(Vel.x, npPlayer->nMass, nMass);
npObj->Vel.y += MulDiv(Vel.y, npPlayer->nMass, nMass);
npPlayer->Vel.x -= MulDiv(Vel.x, npObj->nMass, nMass);
npPlayer->Vel.y -= MulDiv(Vel.y, npObj->nMass, nMass);
if (--npPlayer->nCount) {
npPlayer->byColor = (BYTE) (BLACK + npPlayer->nCount);
if (npPlayer->byColor > WHITE)
npPlayer->byColor = WHITE;
Hit(hDC, npPlayer);
return (TRUE);
}
/* final death */
npPlayer->byColor = WHITE;
Explode(hDC, npPlayer);
SetRestart(RESTART_GAME);
return (FALSE);
}
/*****************************************************************************/
/*CreateLetter - make a new letter object*/
/*****************************************************************************/
NPOBJ APIENTRY
CreateLetter(CHAR cLetter, INT nSize, INT nCount)
{
NPOBJ npLtr;
INT nCnt;
LPSTR lpDesc;
if (cLetter >= '0' && cLetter <= '9')
lpDesc = szNumberDesc[cLetter - '0'];
else if (cLetter >= 'A' && cLetter <= 'Z')
lpDesc = szLetterDesc[cLetter - 'A'];
else if (cLetter >= 'a' && cLetter <= 'z')
lpDesc = szLetterDesc[cLetter - 'a'];
else if (cLetter == '.')
lpDesc = "l";
else
return (NULL);
if (npLtr = RemHeadObj(&FreeList)) {
npLtr->nMass = 1;
npLtr->nDir = 0;
npLtr->nSpin = 0;
npLtr->nCount = nCount;
npLtr->byColor = WHITE;
npLtr->byPts = (BYTE) (nCnt = strlen(lpDesc));
while (nCnt--) {
npLtr->Pts[nCnt] = LetterPart[lpDesc[nCnt] - 'a'];
npLtr->Pts[nCnt].y = MulDiv(npLtr->Pts[nCnt].y, nSize, LETTER_MAX);
}
AddHeadObj(&LetterList, npLtr);
}
return (npLtr);
}
/*****************************************************************************/
/*DrawLetters - draw letters and such*/
/*****************************************************************************/
VOID APIENTRY
DrawLetters(HDC hDC)
{
NPOBJ npLtr, npNext;
for (npLtr = HeadObj(&LetterList); npLtr; npLtr = npNext) {
npNext = NextObj(npLtr);
switch (--npLtr->nCount) {
case 3:
--npLtr->byColor;
break;
case 0:
RemoveObj(&LetterList, npLtr);
AddHeadObj(&FreeList, npLtr);
break;
}
DrawObject(hDC, npLtr);
}
}
/*****************************************************************************/
/*CreateBonus - make a new bonus object*/
/*****************************************************************************/
VOID APIENTRY
CreateBonus(VOID)
{
NPOBJ npBonus;
INT nCnt;
if (npBonus = RemHeadObj(&FreeList)) {
npBonus->Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
npBonus->Pos.y = -CLIP_COORD;
npBonus->Vel.x = npBonus->Vel.y = 0;
npBonus->nDir = arand(DEGREE_SIZE);
npBonus->nSpin = (arand(2) ? 30 : -30);
npBonus->nCount = arand(4) + 1;
npBonus->nDelay = 64 + arand(128);
npBonus->nMass = 768;
npBonus->byColor = (BYTE) (WHITE + (npBonus->nCount * 2));
npBonus->byPts = DIM(Bonus);
for (nCnt = 0; nCnt < DIM(Bonus); ++nCnt)
npBonus->Pts[nCnt] = Bonus[nCnt];
ACCEL(npBonus, npBonus->nDir, 30 + nLevel * 2);
AddHeadObj(&BonusList, npBonus);
}
}
/*****************************************************************************/
/*DrawBonuses - process and draw the bonus list*/
/*****************************************************************************/
VOID APIENTRY
DrawBonuses(HDC hDC)
{
NPOBJ npBonus, npNext;
LOCAL INT nNextBonus = 1000;
if (nBadGuys && (--nNextBonus < 0)) {
CreateBonus();
nNextBonus = 1000;
}
for (npBonus = HeadObj(&BonusList); npBonus; npBonus = npNext) {
NPOBJ npShot;
INT nDelta;
RECT rect;
npNext = NextObj(npBonus);
MKRECT(&rect, npBonus->Pos, 150);
if (PTINRECT(&rect, npPlayer->Pos)) {
if (npPlayer->nCount > 0)
switch (npBonus->nCount) {
case 1:
{
CHAR szBuff[32];
LONG lBonus = 1000L * nLevel;
if (lBonus == 0)
lBonus = 500;
lScore += lBonus;
wsprintf(szBuff, "%ld", lBonus);
PrintPlayerMessage(szBuff);
}
break;
case 2:
nSafe = 15;
++nShield;
npPlayer->byColor = GREEN;
PrintPlayerMessage("EXTRA SHIELD");
break;
case 3:
++nBomb;
PrintPlayerMessage("EXTRA BOMB");
break;
case 4:
AddExtraLife();
break;
}
npBonus->nCount = 0;
Explode(hDC, npBonus);
RemoveObj(&BonusList, npBonus);
AddHeadObj(&FreeList, npBonus);
}
else if (INTRECT(&rect, &rectShotClip)) {
for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
if (!PTINRECT(&rect, npShot->Pos))
continue;
npShot->nCount = 1;
npBonus->nCount = 0;
Explode(hDC, npBonus);
RemoveObj(&BonusList, npBonus);
AddHeadObj(&FreeList, npBonus);
}
}
if (npBonus->nCount && --npBonus->nDelay <= 0) {
--npBonus->nCount;
npBonus->nDelay = 64 + arand(128);
npBonus->byColor = (BYTE) (WHITE + (npBonus->nCount * 2));
if (npBonus->nCount == 0) {
Explode(hDC, npBonus);
RemoveObj(&BonusList, npBonus);
AddHeadObj(&FreeList, npBonus);
}
}
nDelta = npPlayer->Pos.x - npBonus->Pos.x;
while (nDelta < -16 || nDelta > 16)
nDelta /= 2;
npBonus->Vel.x += nDelta - npBonus->Vel.x / 16;
nDelta = npPlayer->Pos.y - npBonus->Pos.y;
while (nDelta < -16 || nDelta > 16)
nDelta /= 2;
npBonus->Vel.y += nDelta - npBonus->Vel.y / 16;
DrawObject(hDC, npBonus);
}
}
/*****************************************************************************/
/*DrawHunterShots - process and draw the hunter shot list*/
/*****************************************************************************/
VOID APIENTRY
DrawHunterShots(HDC hDC)
{
NPOBJ npShot, npNext;
for (npShot = HeadObj(&HunterShotList); npShot; npShot = npNext) {
RECT rect;
npNext = NextObj(npShot);
MKRECT(&rect, npShot->Pos, 200);
if (PTINRECT(&rect, npPlayer->Pos)) {
HitPlayer(hDC, npShot);
npShot->nCount = 1;
}
switch (--npShot->nCount) {
case 7:
npShot->byColor = DKGREEN;
break;
case 0:
RemoveObj(&HunterShotList, npShot);
AddHeadObj(&FreeList, npShot);
break;
}
DrawObject(hDC, npShot);
}
}
/*****************************************************************************/
/*FireHunterShot - fire a hunter bullet*/
/*****************************************************************************/
VOID APIENTRY
FireHunterShot(NPOBJ npHunt)
{
NPOBJ npShot;
if (npShot = RemHeadObj(&FreeList)) {
npShot->Pos.x = npHunt->Pos.x;
npShot->Pos.y = npHunt->Pos.y;
npShot->Vel.x = npHunt->Vel.x;
npShot->Vel.y = npHunt->Vel.y;
npShot->nMass = 80;
npShot->nDir = npHunt->nDir + arand(5) - 2;
npShot->nSpin = (arand(2) ? 10 : -10);
npShot->nCount = 16 + arand(8);
npShot->byColor = GREEN;
npShot->byPts = 2;
npShot->Pts[0].x = 128;
npShot->Pts[0].y = 50;
npShot->Pts[1].x = 0;
npShot->Pts[1].y = 50;
ACCEL(npShot, npShot->nDir, 200 + npShot->nCount);
AddHeadObj(&HunterShotList, npShot);
}
}
/*****************************************************************************/
/*CreateHunter - make a new hunter*/
/*****************************************************************************/
VOID APIENTRY
CreateHunter(VOID)
{
NPOBJ npHunt;
INT nCnt;
if (npHunt = RemHeadObj(&FreeList)) {
npHunt->Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
npHunt->Pos.y = -CLIP_COORD;
npHunt->Vel.x = npHunt->Vel.y = 0;
npHunt->nMass = 16;
npHunt->nDir = arand(DEGREE_SIZE);
npHunt->nSpin = 0;
npHunt->nCount = 1 + arand(nLevel);
npHunt->nDelay = 2 + arand(10);
npHunt->byColor = CYAN;
npHunt->byPts = DIM(Hunter);
for (nCnt = 0; nCnt < DIM(Hunter); ++nCnt)
npHunt->Pts[nCnt] = Hunter[nCnt];
ACCEL(npHunt, npHunt->nDir, arand(500) + nLevel * 50);
AddHeadObj(&HunterList, npHunt);
nBadGuys++;
}
}
/*****************************************************************************/
/*DrawHunters - process and draw the hunter list*/
/*****************************************************************************/
VOID APIENTRY
DrawHunters(HDC hDC)
{
NPOBJ npHunt, npNext;
LOCAL INT nNextHunter = 200;
if (nBadGuys && (--nNextHunter < 0)) {
CreateHunter();
nNextHunter = 1000 + arand(1000) - nLevel * 8;
}
for (npHunt = HeadObj(&HunterList); npHunt; npHunt = npNext) {
NPOBJ npShot;
RECT rect;
npNext = NextObj(npHunt);
MKRECT(&rect, npHunt->Pos, 200);
if (PTINRECT(&rect, npPlayer->Pos)) {
HitPlayer(hDC, npHunt);
--npHunt->nCount;
if (npHunt->nCount < 1) {
KillBadGuy();
npHunt->byColor = CYAN;
Explode(hDC, npHunt);
RemoveObj(&HunterList, npHunt);
AddHeadObj(&FreeList, npHunt);
}
else if (npHunt->nCount == 1)
npHunt->byColor = DKCYAN;
}
else if (INTRECT(&rect, &rectShotClip)) {
for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
if (!PTINRECT(&rect, npShot->Pos))
continue;
npShot->nCount = 1;
lScore += npHunt->nCount * 1000;
if (--npHunt->nCount < 1) {
KillBadGuy();
npHunt->byColor = CYAN;
Explode(hDC, npHunt);
RemoveObj(&HunterList, npHunt);
AddHeadObj(&FreeList, npHunt);
}
else {
if (npHunt->nCount == 1)
npHunt->byColor = DKCYAN;
Hit(hDC, npHunt);
}
break;
}
}
ACCEL(npHunt, npHunt->nDir, 8);
npHunt->Vel.x -= npHunt->Vel.x / 16;
npHunt->Vel.y -= npHunt->Vel.y / 16;
if (--npHunt->nDelay <= 0) {
npHunt->nDelay = arand(10);
npHunt->nSpin = arand(11) - 5;
FireHunterShot(npHunt);
}
DrawObject(hDC, npHunt);
}
}
/*****************************************************************************/
/*CreateSwarmer - make a new swarmer*/
/*****************************************************************************/
VOID APIENTRY
CreateSwarmer(POINT Pos, INT nDir, INT nCount)
{
NPOBJ npSwarm;
INT nCnt;
if (npSwarm = RemHeadObj(&FreeList)) {
npSwarm->Pos = Pos;
npSwarm->Vel.x = npSwarm->Vel.y = 0;
npSwarm->nDir = nDir;
npSwarm->nSpin = arand(31) - 15;
npSwarm->nCount = nCount;
npSwarm->nDelay = 64 + arand(64);
npSwarm->nMass = 32;
npSwarm->byColor = DKGREEN;
npSwarm->byPts = DIM(Swarmer);
for (nCnt = 0; nCnt < DIM(Swarmer); ++nCnt) {
npSwarm->Pts[nCnt] = Swarmer[nCnt];
npSwarm->Pts[nCnt].y += nCount * 10;
}
ACCEL(npSwarm, npSwarm->nDir, 30 + nLevel * 2);
AddHeadObj(&SwarmerList, npSwarm);
nBadGuys++;
}
}
/*****************************************************************************/
/*DrawSwarmers - process and draw the swarmer list*/
/*****************************************************************************/
VOID APIENTRY
DrawSwarmers(HDC hDC)
{
NPOBJ npSwarm, npNext;
LOCAL INT nNextSwarmer = 1000;
if (nBadGuys && (--nNextSwarmer < 0)) {
POINT Pos;
Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
Pos.y = -CLIP_COORD;
CreateSwarmer(Pos, arand(DEGREE_SIZE), 8 + nLevel * 2);
nNextSwarmer = 1000 + arand(500) - nLevel * 4;
}
for (npSwarm = HeadObj(&SwarmerList); npSwarm; npSwarm = npNext) {
NPOBJ npShot;
RECT rect;
npNext = NextObj(npSwarm);
MKRECT(&rect, npSwarm->Pos, 150 + npSwarm->nCount * 10);
if (PTINRECT(&rect, npPlayer->Pos)) {
HitPlayer(hDC, npSwarm);
npSwarm->nCount = 0;
}
else if (INTRECT(&rect, &rectShotClip)) {
for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
if (!PTINRECT(&rect, npShot->Pos))
continue;
npShot->nCount = 1;
lScore += npSwarm->nCount * 25;
npSwarm->nCount = 0;
break;
}
}
if (npSwarm->nCount <= 0) {
npSwarm->byColor = GREEN;
KillBadGuy();
Explode(hDC, npSwarm);
RemoveObj(&SwarmerList, npSwarm);
AddHeadObj(&FreeList, npSwarm);
}
else {
if ((npSwarm->nCount > 1) && (--npSwarm->nDelay <= 0)) {
INT nDir = arand(DEGREE_SIZE);
INT nCount = npSwarm->nCount / 2;
CreateSwarmer(npSwarm->Pos, nDir, nCount);
nCount = npSwarm->nCount - nCount;
CreateSwarmer(npSwarm->Pos, nDir + 128, nCount);
npSwarm->nCount = 0;
}
DrawObject(hDC, npSwarm);
}
}
}
/*****************************************************************************/
/*CreateSpinner - make a new spinner*/
/*****************************************************************************/
VOID APIENTRY
CreateSpinner(VOID)
{
NPOBJ npSpin;
INT nCnt;
if (npSpin = RemHeadObj(&FreeList)) {
npSpin->Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
npSpin->Pos.y = -CLIP_COORD;
npSpin->Vel.x = npSpin->Vel.y = 0;
npSpin->nDir = arand(DEGREE_SIZE);
npSpin->nSpin = -12;
npSpin->nCount = 1 + arand(nLevel);
npSpin->nMass = 64 + npSpin->nCount * 32;
npSpin->byColor = (BYTE) (MAGENTA - npSpin->nCount);
npSpin->byPts = DIM(Spinner);
for (nCnt = 0; nCnt < DIM(Spinner); ++nCnt)
npSpin->Pts[nCnt] = Spinner[nCnt];
ACCEL(npSpin, npSpin->nDir, 30 + nLevel * 2);
AddHeadObj(&SpinnerList, npSpin);
++nBadGuys;
}
}
/*****************************************************************************/
/*DrawSpinners - process and draw the spinner list*/
/*****************************************************************************/
VOID APIENTRY
DrawSpinners(HDC hDC)
{
NPOBJ npSpin, npNext;
LOCAL INT nNextSpinner = 1000;
if (nBadGuys && (--nNextSpinner < 0)) {
CreateSpinner();
nNextSpinner = 100 + arand(900) - nLevel * 2;
}
for (npSpin = HeadObj(&SpinnerList); npSpin; npSpin = npNext) {
NPOBJ npShot;
INT nDelta;
RECT rect;
npNext = NextObj(npSpin);
MKRECT(&rect, npSpin->Pos, 150);
if (PTINRECT(&rect, npPlayer->Pos)) {
HitPlayer(hDC, npSpin);
--npSpin->nCount;
npSpin->byColor = (BYTE) (MAGENTA - npSpin->nCount);
if (npSpin->nCount < 1) {
KillBadGuy();
Explode(hDC, npSpin);
RemoveObj(&SpinnerList, npSpin);
AddHeadObj(&FreeList, npSpin);
}
}
else if (INTRECT(&rect, &rectShotClip)) {
for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
if (!PTINRECT(&rect, npShot->Pos))
continue;
npShot->nCount = 1;
lScore += npSpin->nCount * 500;
npSpin->byColor = (BYTE) (MAGENTA - (--npSpin->nCount));
if (npSpin->nCount < 1) {
KillBadGuy();
Explode(hDC, npSpin);
RemoveObj(&SpinnerList, npSpin);
AddHeadObj(&FreeList, npSpin);
}
else
Hit(hDC, npSpin);
break;
}
}
nDelta = npPlayer->Pos.x - npSpin->Pos.x;
while (nDelta < -16 || nDelta > 16)
nDelta /= 2;
npSpin->Vel.x += nDelta - npSpin->Vel.x / 16;
nDelta = npPlayer->Pos.y - npSpin->Pos.y;
while (nDelta < -16 || nDelta > 16)
nDelta /= 2;
npSpin->Vel.y += nDelta - npSpin->Vel.y / 16;
DrawObject(hDC, npSpin);
}
}
/*****************************************************************************/
/*CreateRoid - make a new asteroid*/
/*****************************************************************************/
VOID APIENTRY
CreateRoid(POINT Pos, POINT Vel, INT nSides, BYTE byColor, INT nDir,
INT nSpeed, INT nSpin)
{
NPOBJ npRoid;
INT nCnt;
if (npRoid = RemHeadObj(&FreeList)) {
npRoid->Pos = Pos;
npRoid->Vel = Vel;
npRoid->nMass = nSides * 128;
npRoid->nDir = nDir;
npRoid->nSpin = nSpin + arand(11) - 5;
npRoid->nCount = nSides * 100;
npRoid->byColor = byColor;
npRoid->byPts = (BYTE) (nSides + 1);
for (nCnt = 0; nCnt < nSides; ++nCnt) {
npRoid->Pts[nCnt].x = nCnt * DEGREE_SIZE / nSides + arand(30);
npRoid->Pts[nCnt].y = (nSides - 1) * 100 + 20 + arand(80);
}
npRoid->Pts[nSides] = npRoid->Pts[0];
ACCEL(npRoid, nDir, nSpeed);
AddHeadObj(&RoidList, npRoid);
++nBadGuys;
}
}
/*****************************************************************************/
/*BreakRoid - break up an asteroid*/
/*****************************************************************************/
VOID APIENTRY
BreakRoid(HDC hDC, NPOBJ npRoid, NPOBJ npShot)
{
INT nCnt, nNew;
lScore += npRoid->nCount;
if (npShot)
npShot->nCount = 1;
switch (npRoid->byPts) {
case 8:
nNew = 2 + arand(3);
break;
case 7:
nNew = 1 + arand(3);
break;
case 6:
nNew = 1 + arand(2);
break;
case 5:
nNew = arand(2);
break;
default:
nNew = 0;
break;
}
if (nNew == 1 && npShot) { /* don't explode outward */
POINT Pt = npRoid->Pos;
Pt.x += arand(301) - 150;
Pt.y += arand(301) - 150;
CreateRoid(Pt, npRoid->Vel, npRoid->byPts - (nNew + 1),
npRoid->byColor, npShot->nDir, 8, npRoid->nSpin);
}
else if (nNew > 0) {
INT nSpeed = npRoid->nSpin * npRoid->nSpin * nNew + 16;
for (nCnt = 0; nCnt < nNew; ++nCnt) {
POINT Pt = npRoid->Pos;
Pt.x += arand(601) - 300;
Pt.y += arand(601) - 300;
CreateRoid(Pt, npRoid->Vel, npRoid->byPts - (nNew + 1),
npRoid->byColor,
npRoid->nDir + nCnt * DEGREE_SIZE / nNew + arand(32),
nSpeed + arand(nLevel * 4),
npRoid->nSpin / 2);
}
}
KillBadGuy();
++npRoid->byColor;
npRoid->nCount = 0;
if (nNew) {
Hit(hDC, npRoid);
DrawObject(hDC, npRoid);
}
else
Explode(hDC, npRoid);
RemoveObj(&RoidList, npRoid);
AddHeadObj(&FreeList, npRoid);
}
/****************************************************************************'*/
/*DrawRoids - process and draw the asteroid list*/
/*****************************************************************************/
VOID APIENTRY
DrawRoids(HDC hDC)
{
NPOBJ npRoid, npNext;
for (npRoid = HeadObj(&RoidList); npRoid; npRoid = npNext) {
INT nSize = npRoid->nCount;
NPOBJ npShot;
RECT rect;
npNext = NextObj(npRoid);
DrawObject(hDC, npRoid);
MKRECT(&rect, npRoid->Pos, nSize);
if (PTINRECT(&rect, npPlayer->Pos) && HitPlayer(hDC, npRoid)) {
npPlayer->nCount = -npPlayer->nCount;
npPlayer->byColor = WHITE;
Explode(hDC, npPlayer);
BreakRoid(hDC, npRoid, NULL);
if (nBadGuys)
SetRestart(RESTART_LEVEL);
else
SetRestart(RESTART_NEXTLEVEL);
}
else if (INTRECT(&rect, &rectShotClip)) {
for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
if (!PTINRECT(&rect, npShot->Pos))
continue;
BreakRoid(hDC, npRoid, npShot);
break;
}
}
}
}
/*****************************************************************************/
/*DrawShots - process and draw the player shot list*/
/*****************************************************************************/
VOID APIENTRY
DrawShots(HDC hDC)
{
NPOBJ npShot, npNext;
if (npShot = HeadObj(&ShotList)) {
rectShotClip.left = rectShotClip.right = npShot->Pos.x;
rectShotClip.top = rectShotClip.bottom = npShot->Pos.y;
while (npShot) {
npNext = NextObj(npShot);
switch (--npShot->nCount) {
case 10:
npShot->byColor = DKCYAN;
break;
case 5:
npShot->byColor = DKBLUE;
break;
case 0:
RemoveObj(&ShotList, npShot);
AddHeadObj(&FreeList, npShot);
break;
}
DrawObject(hDC, npShot);
if (npShot->Pos.x < rectShotClip.left)
rectShotClip.left = npShot->Pos.x;
else if (npShot->Pos.x > rectShotClip.right)
rectShotClip.right = npShot->Pos.x;
if (npShot->Pos.y < rectShotClip.top)
rectShotClip.top = npShot->Pos.y;
else if (npShot->Pos.y > rectShotClip.bottom)
rectShotClip.bottom = npShot->Pos.y;
npShot = npNext;
}
}
else
rectShotClip.left = rectShotClip.right = rectShotClip.top = rectShotClip.bottom = 32767;
}
/*****************************************************************************/
/*DrawFlames - process and draw the flame list*/
/*****************************************************************************/
VOID APIENTRY
DrawFlames(HDC hDC)
{
NPOBJ npFlame, npNext;
for (npFlame = HeadObj(&FlameList); npFlame; npFlame = npNext) {
npNext = NextObj(npFlame);
switch (--npFlame->nCount) {
case 7:
npFlame->byColor = RED;
break;
case 3:
npFlame->byColor = DKRED;
break;
case 0:
RemoveObj(&FlameList, npFlame);
AddHeadObj(&FreeList, npFlame);
break;
}
DrawObject(hDC, npFlame);
}
}
/*****************************************************************************/
/*FireShot - fire a bullet*/
/*****************************************************************************/
VOID APIENTRY
FireShot(VOID)
{
NPOBJ npShot;
if (npShot = RemHeadObj(&FreeList)) {
npShot->Pos.x = npPlayer->Pos.x;
npShot->Pos.y = npPlayer->Pos.y;
npShot->Vel.x = npPlayer->Vel.x;
npShot->Vel.y = npPlayer->Vel.y;
npShot->nMass = 80;
npShot->nDir = npPlayer->nDir + arand(3) - 2;
npShot->nSpin = (arand(2) ? 30 : -30);
npShot->nCount = 16 + arand(8);
npShot->byColor = CYAN;
npShot->byPts = 2;
npShot->Pts[0].x = 128;
npShot->Pts[0].y = 50;
npShot->Pts[1].x = 0;
npShot->Pts[1].y = 50;
ACCEL(npShot, npShot->nDir, 200 + npShot->nCount);
AddHeadObj(&ShotList, npShot);
}
}
/*****************************************************************************/
/*AccelPlayer - move the player forward*/
/*****************************************************************************/
VOID APIENTRY
AccelPlayer(INT nDir, INT nAccel)
{
NPOBJ npFlame;
nDir += npPlayer->nDir;
if (nAccel)
ACCEL(npPlayer, nDir, nAccel);
if (npFlame = RemHeadObj(&FreeList)) {
npFlame->Pos.x = npPlayer->Pos.x;
npFlame->Pos.y = npPlayer->Pos.y;
npFlame->Vel.x = npPlayer->Vel.x;
npFlame->Vel.y = npPlayer->Vel.y;
npFlame->nDir = nDir + 100 + arand(57);
npFlame->nSpin = 0;
npFlame->nCount = nAccel + arand(7);
npFlame->byColor = YELLOW;
npFlame->byPts = 1;
npFlame->Pts[0].x = npFlame->Pts[0].y = 0;
ACCEL(npFlame, npFlame->nDir, 50 + arand(10));
AddHeadObj(&FlameList, npFlame);
}
}
/*****************************************************************************/
/*DrawPlayer - process and draw the player*/
/*****************************************************************************/
VOID APIENTRY
DrawPlayer(HDC hDC)
{
LOCAL INT nBombing = 0;
LOCAL INT nShotDelay = 0;
if (npPlayer->nCount <= 0)
return;
if (nSafe > 0) {
if (--nSafe == 0) {
npPlayer->byColor = (BYTE) (BLACK + npPlayer->nCount);
if (npPlayer->byColor > WHITE)
npPlayer->byColor = WHITE;
}
}
else if (IsKeyDown(vkShld) && nShield > 0) {
nSafe = 15;
if (--nShield > 0)
npPlayer->byColor = GREEN;
else
npPlayer->byColor = DKGREEN;
}
if (nBombing > 0) {
if (--nBombing == 0) {
ExplodeBadguys(hDC, &SpinnerList);
ExplodeBadguys(hDC, &SwarmerList);
ExplodeBadguys(hDC, &HunterList);
}
else {
HitList(hDC, &SpinnerList);
/* HitList( hDC, &SwarmerList ); */
HitList(hDC, &HunterList);
}
}
else if (nBomb && IsKeyDown(vkBomb))
--nBomb, nBombing = 5;
if (IsKeyDown(vkClkw))
npPlayer->nSpin += 6;
if (IsKeyDown(vkCtrClkw))
npPlayer->nSpin -= 6;
if (IsKeyDown(vkThrst))
AccelPlayer(0, 12);
if (IsKeyDown(vkRvThrst))
AccelPlayer(128, 12);
if (nShotDelay)
--nShotDelay;
else if (IsKeyDown(vkFire))
FireShot(), nShotDelay = 2;
DrawObject(hDC, npPlayer);
npPlayer->nSpin /= 2;
}
/*****************************************************************************/
/*GetHyperoidDC - get the correct DC for hyperoid rendering*/
/*****************************************************************************/
HDC APIENTRY
GetHyperoidDC(HWND hWnd)
{
HDC hDC;
INT cx, cy;
RECT rect;
GetClientRect(hWnd, &rect);
cx = rect.right - rect.left;
cy = rect.bottom - rect.top;
hDC = GetDC(hWnd);
/* set up the mapping mode */
SetMapMode(hDC, MM_ISOTROPIC);
SetWindowExt(hDC, MAX_COORD, MAX_COORD);
SetViewportExt(hDC, cx / 2, -cy / 2);
SetViewportOrg(hDC, cx / 2, cy / 2);
/* realize the palette */
SelectPalette(hDC, hAppPalette, 0);
RealizePalette(hDC);
return (hDC);
}
/*****************************************************************************/
/*DrawObjects - transform and redraw everything in the system*/
/*****************************************************************************/
VOID APIENTRY
DrawObjects(HWND hWnd)
{
HDC hDC = GetHyperoidDC(hWnd);
/* move and draw things (I don't think the order is important...) */
DrawPlayer(hDC);
DrawFlames(hDC);
DrawShots(hDC);
DrawRoids(hDC);
DrawSpinners(hDC);
DrawSwarmers(hDC);
DrawHunters(hDC);
DrawHunterShots(hDC);
DrawLetters(hDC);
DrawBonuses(hDC);
/* (...but I'm not changing it!!! :-) */
ReleaseDC(hWnd, hDC);
}
/*****************************************************************************/
/*SetIndicator - set a quantity indicator*/
/*****************************************************************************/
INT APIENTRY
SetIndicator(LPSTR lpBuff, CHAR IDBitmap, INT nQuant)
{
if (nQuant > 5) {
*lpBuff++ = IDBitmap;
*lpBuff++ = IDBitmap;
*lpBuff++ = IDBitmap;
*lpBuff++ = IDBitmap;
*lpBuff++ = IDB_plus;
}
else {
INT nBlank = 5 - nQuant;
while (nQuant--)
*lpBuff++ = IDBitmap;
while (nBlank--)
*lpBuff++ = IDB_blank;
}
return (5);
}
/*****************************************************************************/
/*CheckScore - show the score and such stuff*/
/*****************************************************************************/
VOID APIENTRY
CheckScore(HWND hWnd)
{
CHAR szBuff[sizeof(szScore)];
LPSTR lpBuff = szBuff;
INT nLives, nLen, nCnt, x, y;
HBITMAP hbmOld;
HDC hDC, hDCMem;
if (IsIconic(hWnd))
return;
if (lScore - lLastLife > EXTRA_LIFE) {
AddExtraLife();
lLastLife = lScore;
}
nLives = ((npPlayer->nCount > 0) ? npPlayer->nCount : -npPlayer->nCount);
*lpBuff++ = IDB_level;
wsprintf(lpBuff, "%2.2u", nLevel);
while (isdigit(*lpBuff))
*lpBuff = (CHAR) (*lpBuff + IDB_num0 - '0'), ++lpBuff;
*lpBuff++ = IDB_blank;
*lpBuff++ = IDB_score;
wsprintf(lpBuff, "%7.7lu", lScore);
while (isdigit(*lpBuff))
*lpBuff = (CHAR) (*lpBuff + IDB_num0 - '0'), ++lpBuff;
*lpBuff++ = IDB_blank;
lpBuff += SetIndicator(lpBuff, IDB_life, nLives);
lpBuff += SetIndicator(lpBuff, IDB_shield, nShield);
lpBuff += SetIndicator(lpBuff, IDB_bomb, nBomb);
nLen = lpBuff - szBuff;
hDC = GetWindowDC(hWnd);
IntersectClipRect(hDC, rectScoreClip.left, rectScoreClip.top,
rectScoreClip.right, rectScoreClip.bottom);
hDCMem = CreateCompatibleDC(hDC);
hbmOld = SelectObject(hDCMem, hBitmap[0]);
x = rectScoreClip.left;
y = rectScoreClip.top;
for (nCnt = 0; nCnt < nLen; ++nCnt) {
if (szBuff[nCnt] != szScore[nCnt]) {
SelectObject(hDCMem, hBitmap[szBuff[nCnt] - IDB_blank]);
BitBlt(hDC, x, y, CX_BITMAP, CY_BITMAP, hDCMem, 0, 0, SRCCOPY);
szScore[nCnt] = szBuff[nCnt];
}
x += CX_BITMAP;
}
if (nCnt < nScoreLen) {
SelectObject(hDCMem, hBitmap[0]);
do {
if (szScore[nCnt] != IDB_blank) {
BitBlt(hDC, x, y, CX_BITMAP, CY_BITMAP, hDCMem, 0, 0, SRCCOPY);
szScore[nCnt] = IDB_blank;
}
x += CX_BITMAP;
} while (++nCnt < nScoreLen);
}
nScoreLen = nLen;
SelectObject(hDCMem, hbmOld);
DeleteDC(hDCMem);
ReleaseDC(hWnd, hDC);
}
/*****************************************************************************/
/*HitList - Hit() a list of things*/
/*****************************************************************************/
VOID APIENTRY
HitList(HDC hDC, NPLIST npList)
{
NPOBJ npObj;
for (npObj = HeadObj(npList); npObj; npObj = NextObj(npObj))
if (npObj->nCount)
Hit(hDC, npObj);
}
/*****************************************************************************/
/*ExplodeBadguys - explode a list of badguys*/
/*****************************************************************************/
VOID APIENTRY
ExplodeBadguys(HDC hDC, NPLIST npList)
{
NPOBJ npObj;
while (npObj = HeadObj(npList)) {
KillBadGuy();
npObj->nCount = 0;
Explode(hDC, npObj);
RemoveObj(npList, npObj);
AddHeadObj(&FreeList, npObj);
}
}
/*****************************************************************************/
/*NewGame - start a new game*/
/*****************************************************************************/
VOID APIENTRY
NewGame(HWND hWnd)
{
HDC hDC = GetHyperoidDC(hWnd);
npPlayer->nCount = 0;
npPlayer->byColor = WHITE;
Explode(hDC, npPlayer);
SetRestart(RESTART_GAME);
ExplodeBadguys(hDC, &RoidList);
ExplodeBadguys(hDC, &SpinnerList);
ExplodeBadguys(hDC, &SwarmerList);
ExplodeBadguys(hDC, &HunterList);
ReleaseDC(hWnd, hDC);
}
/*****************************************************************************/
/*RestartHyperoid - set up a game!*/
/*****************************************************************************/
VOID APIENTRY
RestartHyperoid(VOID)
{
if (npPlayer->nCount == 0) {
POINT Pos, Vel;
Pos.x = 0;
Pos.y = -CLIP_COORD / 2;
Vel.x = 0;
Vel.y = 150;
PrintLetters(szAppName, Pos, Vel, YELLOW, 800);
npPlayer->nCount = 3;
if (lHighScore < lScore)
lHighScore = lScore;
lLastLife = lScore = 0;
nLevel = 0;
nShield = nBomb = 3;
}
else if (npPlayer->nCount < 0) {
/* cheesy way of restarting after a major collision */
npPlayer->nCount = -npPlayer->nCount;
nShield = nBomb = 3;
}
npPlayer->Pos.x = npPlayer->Pos.y = 0;
npPlayer->Vel.x = npPlayer->Vel.y = 0;
npPlayer->nDir = 64;
npPlayer->nSpin = 0;
npPlayer->byColor = GREEN;
nSafe = 30;
if (ShotList.npHead) {
NPOBJ npShot;
for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot))
npShot->nCount = 1;
}
/* reseed the asteroid field */
if (nBadGuys == 0) {
INT nCnt;
++nLevel;
for (nCnt = 8 + nLevel; nCnt; --nCnt) {
POINT Pos, Vel;
Pos.x = arand(MAX_COORD * 2) - MAX_COORD;
Pos.y = arand(MAX_COORD * 2) - MAX_COORD;
Vel.x = Vel.y = 0;
CreateRoid(Pos, Vel, 3 + arand(4),
(BYTE) (arand(2) ? DKYELLOW : DKGREY),
arand(DEGREE_MAX), 12 + arand(nLevel * 2), arand(5));
}
}
}
/*****************************************************************************/
/*Panic - boss key (or just pause)*/
/*****************************************************************************/
VOID APIENTRY
Panic(BOOL bPanic)
{
if (bPanic && !bPaused) {
bPaused = TRUE;
KillTimer(hAppWnd, DRAW_TIMER);
SetWindowText(hAppWnd, "Program Manager Help - PROGMAN.HLP");
ShowWindow(hAppWnd, SW_SHOWMINNOACTIVE);
InvalidateRect(hAppWnd, NULL, TRUE);
}
else if (bPaused) { /* double-panic == normal */
bPaused = FALSE;
SetWindowText(hAppWnd, szAppName);
if (bPanic)
ShowWindow(hAppWnd, SW_RESTORE);
SetTimer(hAppWnd, DRAW_TIMER, nDrawDelay, NULL);
}
}
/*****************************************************************************/
/*PaintHyperoid - paint the hyperoid window*/
/*****************************************************************************/
VOID APIENTRY
PaintHyperoid(HWND hWnd)
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
if (bPaused)
DrawIcon(ps.hdc, 2, 2, LoadIcon(hAppInst, INTRES(IDI_PANIC)));
EndPaint(hWnd, &ps);
}
/*****************************************************************************/
/*EraseHyperoidBkgnd - fill in the background*/
/*****************************************************************************/
BOOL APIENTRY
EraseHyperoidBkgnd(HWND hWnd, HDC hDC)
{
HBRUSH hbr;
RECT rect;
GetClientRect(hWnd, &rect);
if (bPaused) {
#ifdef WIN32
SetBrushOrgEx(hDC, 0, 0, NULL);
#else
SetBrushOrg(hDC, 0, 0);
#endif
hbr = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
}
else {
SelectPalette(hDC, hAppPalette, 0);
RealizePalette(hDC);
hbr = CreateSolidBrush(PALETTEINDEX(BLACK));
}
FillRect(hDC, &rect, hbr);
DeleteObject(hbr);
return (TRUE);
}
/*****************************************************************************/
/*DrawShadowRect - draw a shaded rectangle around an object*/
/*****************************************************************************/
VOID APIENTRY
DrawShadowRect(HDC hDC, LPRECT lpRect, HPEN hHi, HPEN hLo)
{
SelectObject(hDC, hHi);
MoveTo(hDC, lpRect->right, lpRect->top);
LineTo(hDC, lpRect->left, lpRect->top);
LineTo(hDC, lpRect->left, lpRect->bottom);
SelectObject(hDC, hLo);
LineTo(hDC, lpRect->right, lpRect->bottom);
LineTo(hDC, lpRect->right, lpRect->top);
}
/*****************************************************************************/
/*NCPaintHyperoid - paint a custom frame*/
/*****************************************************************************/
VOID APIENTRY
NCPaintHyperoid(HWND hWnd)
{
HDC hDC, hDCMem;
INT cx, cy, cyCap, h;
HPEN hpenHi, hpenLo;
HBRUSH hbr;
HBITMAP hbm, hbmOld;
BITMAP bm;
RECT rect;
if (IsIconic(hWnd))
return;
hDC = GetWindowDC(hWnd);
GetWindowRect(hWnd, &rect);
rect.right -= rect.left, rect.left = 0;
rect.bottom -= rect.top, rect.top = 0;
cx = GetSystemMetrics(SM_CXFRAME);
cy = GetSystemMetrics(SM_CYFRAME);
cyCap = cy + GetSystemMetrics(SM_CYCAPTION) - 1;
h = rect.bottom - (cyCap + cy);
SelectPalette(hDC, hAppPalette, 0);
RealizePalette(hDC);
if (bBW) {
hbr = SelectObject(hDC, CreateSolidBrush(PALETTEINDEX(WHITE)));
hpenHi = hPen[BLACK];
hpenLo = hPen[BLACK];
}
else {
hbr = SelectObject(hDC, CreateSolidBrush(PALETTEINDEX(GREY)));
hpenHi = hPen[WHITE];
hpenLo = hPen[DKGREY];
}
PatBlt(hDC, 0, 0, rect.right, cyCap, PATCOPY);
PatBlt(hDC, 0, rect.bottom - cy, rect.right, rect.bottom, PATCOPY);
PatBlt(hDC, 0, cyCap, cx, h, PATCOPY);
PatBlt(hDC, rect.right - cx, cyCap, cx, h, PATCOPY);
--rect.bottom;
--rect.right;
DrawShadowRect(hDC, &rect, hpenHi, hpenLo);
--cx;
--cy;
rect.left += cx;
rect.top += cy;
rect.right -= cx;
rect.bottom -= cy;
if (!bBW)
DrawShadowRect(hDC, &rect, hpenLo, hpenHi);
/* get the title bar rect */
++rect.left;
++rect.top;
--rect.right;
rect.bottom = rect.top + cyCap - (cy + 2);
DrawShadowRect(hDC, &rect, hpenHi, hpenLo);
++rect.right; /* for zoom/restore bitmap */
hDCMem = CreateCompatibleDC(hDC);
hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_CLOSE));
GetObject(hbm, sizeof(bm), (LPSTR) & bm);
bm.bmWidth /= 2; /* they packed two images in here! */
hbmOld = SelectObject(hDCMem, hbm);
BitBlt(hDC, rect.left, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY);
rect.left += bm.bmWidth;
if (IsZoomed(hWnd))
hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_RESTORE));
else
hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_ZOOM));
GetObject(hbm, sizeof(bm), (LPSTR) & bm);
SelectObject(hDCMem, hbm);
rect.right -= bm.bmWidth;
BitBlt(hDC, rect.right, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY);
hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_REDUCE));
GetObject(hbm, sizeof(bm), (LPSTR) & bm);
SelectObject(hDCMem, hbm);
rect.right -= bm.bmWidth;
BitBlt(hDC, rect.right, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY);
--rect.right;
DrawShadowRect(hDC, &rect, hpenHi, hpenLo);
/* clip the score to the free titlebar area */
++rect.left;
++rect.top;
rectScoreClip = rect;
DeleteObject(SelectObject(hDCMem, hbmOld));
DeleteObject(SelectObject(hDC, hbr));
DeleteDC(hDCMem);
ReleaseDC(hWnd, hDC);
/* make sure the score gets redrawn */
for (cx = 0; cx < nScoreLen; ++cx)
szScore[cx] = '\0';
}
/*****************************************************************************/
/*InitHyperoid - initialize everything*/
/*****************************************************************************/
BOOL APIENTRY
InitHyperoid(VOID)
{
DOUBLE dRad;
INT nCnt;
/* allocate the logical palette */
hAppPalette = CreateHyperoidPalette();
if (!hAppPalette)
return (FALSE);
for (nCnt = 0; nCnt < PALETTE_SIZE; ++nCnt) {
hPen[nCnt] = CreatePen(PS_SOLID, 1, PALETTEINDEX(nCnt));
if (!hPen[nCnt])
return (FALSE);
}
for (nCnt = 0; nCnt < IDB_MAX; ++nCnt) {
hBitmap[nCnt] = LoadBitmap(hAppInst, INTRES(IDB_blank + nCnt));
if (!hBitmap[nCnt])
return (FALSE);
}
/* seed the randomizer */
dwSeed = GetCurrentTime();
/* create the lookup table (should use resources) */
for (nCnt = 0; nCnt < DEGREE_SIZE; ++nCnt) {
dRad = nCnt * 6.2831855 / DEGREE_SIZE;
nCos[nCnt] = (INT) (DEGREE_MAX * cos(dRad));
nSin[nCnt] = (INT) (DEGREE_MAX * sin(dRad));
}
/* get the initialization file info */
GetHyperoidIni();
/* allocate all objects as free */
for (nCnt = 0; nCnt < MAX_OBJS; ++nCnt)
AddHeadObj(&FreeList, &(Obj[nCnt]));
/* set up the player */
npPlayer = RemHeadObj(&FreeList);
npPlayer->byPts = DIM(Player);
npPlayer->nMass = 0;
for (nCnt = 0; nCnt < DIM(Player); ++nCnt)
npPlayer->Pts[nCnt] = Player[nCnt];
return (TRUE);
}
/*****************************************************************************/
/*ExitHyperoid - quit the damn game already!*/
/*****************************************************************************/
VOID APIENTRY
ExitHyperoid(VOID)
{
INT nCnt;
if (hAppPalette)
DeleteObject(hAppPalette);
for (nCnt = 0; nCnt < PALETTE_SIZE; ++nCnt)
if (hPen[nCnt])
DeleteObject(hPen[nCnt]);
for (nCnt = 0; nCnt < IDB_MAX; ++nCnt)
if (hBitmap[nCnt])
DeleteObject(hBitmap[nCnt]);
}